Set working directory and load necessary packages.
Load the data for March. Load each file and combine into one data set. We load and combine each file in H:/Projects/11000/11155/TraffStudy/DataCollection/FreewayData/Detector Data/Volume Data/Day_selection. We only want to load the files that end in “_#.csv“.
[1] "Combined_March.csv" "March_1.csv" "March_10.csv" "March_11.csv"
[5] "March_12.csv" "March_18" "March_2.csv" "March_3.csv"
[9] "March_4.csv" "March_5.csv" "March_6.csv" "March_7.csv"
[13] "March_8.csv" "March_9.csv"
The column names in each file are also follows.
[1] "X" "X.1" "X.2" "X12.15.AM" "X12.30.AM" "X12.45.AM" "X1.AM"
[8] "X1.15.AM" "X1.30.AM" "X1.45.AM" "X2.AM" "X2.15.AM" "X2.30.AM" "X2.45.AM"
[15] "X3.AM" "X3.15.AM" "X3.30.AM" "X3.45.AM" "X4.AM" "X4.15.AM" "X4.30.AM"
[22] "X4.45.AM" "X5.AM" "X5.15.AM" "X5.30.AM" "X5.45.AM" "X6.AM" "X6.15.AM"
[29] "X6.30.AM" "X6.45.AM" "X7.AM" "X7.15.AM" "X7.30.AM" "X7.45.AM" "X8.AM"
[36] "X8.15.AM" "X8.30.AM" "X8.45.AM" "X9.AM" "X9.15.AM" "X9.30.AM" "X9.45.AM"
[43] "X10.AM" "X10.15.AM" "X10.30.AM" "X10.45.AM" "X11.AM" "X11.15.AM" "X11.30.AM"
[50] "X11.45.AM" "Noon" "X12.15.PM" "X12.30.PM" "X12.45.PM" "X1.PM" "X1.15.PM"
[57] "X1.30.PM" "X1.45.PM" "X2.PM" "X2.15.PM" "X2.30.PM" "X2.45.PM" "X3.PM"
[64] "X3.15.PM" "X3.30.PM" "X3.45.PM" "X4.PM" "X4.15.PM" "X4.30.PM" "X4.45.PM"
[71] "X5.PM" "X5.15.PM" "X5.30.PM" "X5.45.PM" "X6.PM" "X6.15.PM" "X6.30.PM"
[78] "X6.45.PM" "X7.PM" "X7.15.PM" "X7.30.PM" "X7.45.PM" "X8.PM" "X8.15.PM"
[85] "X8.30.PM" "X8.45.PM" "X9.PM" "X9.15.PM" "X9.30.PM" "X9.45.PM" "X10.PM"
[92] "X10.15.PM" "X10.30.PM" "X10.45.PM" "X11.PM" "X11.15.PM" "X11.30.PM" "X11.45.PM"
[99] "Midnight" "X.3" "filename"
Lets fix the column headers first. There are no headers for the first 3 columns and also there appears to be a column at the end of the data frame “X.3”
summary(March_18_dat$X.3)
Mode NA's
logical 39990
All NAs…. remove.
Focus on the first three columns;
'data.frame': 39990 obs. of 3 variables:
$ X : int 1180 1180 1180 1180 1180 1180 1180 1180 1180 1180 ...
$ X.1: chr "Density" "Density" "Density" "Density" ...
$ X.2: chr "2018/03/01" "2018/03/02" "2018/03/03" "2018/03/04" ...
Column 1 is the detector ID.
Column 2 is the metric.
Column 3 is the date.
Now lets change the data types in the columns.
We create a correctly formatted date field from the ‘Date’ field.
We label the field with displays the records type i.e. Density vs Speed vs Volume as ‘Metric’ and change it from a string to a factor field.
We also change Detector_ID from a numeric field to a factor field.
colnames(March_18_dat)
[1] "Detector_ID" "Metric" "Date" "Date_Posixct" "filename" "X12.15.AM" "X12.30.AM" "X12.45.AM"
[9] "X1.00.AM" "X1.15.AM" "X1.30.AM" "X1.45.AM" "X2.00.AM" "X2.15.AM" "X2.30.AM" "X2.45.AM"
[17] "X3.00.AM" "X3.15.AM" "X3.30.AM" "X3.45.AM" "X4.00.AM" "X4.15.AM" "X4.30.AM" "X4.45.AM"
[25] "X5.00.AM" "X5.15.AM" "X5.30.AM" "X5.45.AM" "X6.00.AM" "X6.15.AM" "X6.30.AM" "X6.45.AM"
[33] "X7.00.AM" "X7.15.AM" "X7.30.AM" "X7.45.AM" "X8.00.AM" "X8.15.AM" "X8.30.AM" "X8.45.AM"
[41] "X9.00.AM" "X9.15.AM" "X9.30.AM" "X9.45.AM" "X10.00.AM" "X10.15.AM" "X10.30.AM" "X10.45.AM"
[49] "X11.00.AM" "X11.15.AM" "X11.30.AM" "X11.45.AM" "X1.00.PM" "X12.15.PM" "X12.30.PM" "X12.45.PM"
[57] "X2.00.PM" "X1.15.PM" "X1.30.PM" "X1.45.PM" "X3.00.PM" "X2.15.PM" "X2.30.PM" "X2.45.PM"
[65] "X4.00.PM" "X3.15.PM" "X3.30.PM" "X3.45.PM" "X5.00.PM" "X4.15.PM" "X4.30.PM" "X4.45.PM"
[73] "X6.00.PM" "X5.15.PM" "X5.30.PM" "X5.45.PM" "X7.00.PM" "X6.15.PM" "X6.30.PM" "X6.45.PM"
[81] "X8.00.PM" "X7.15.PM" "X7.30.PM" "X7.45.PM" "X9.00.PM" "X8.15.PM" "X8.30.PM" "X8.45.PM"
[89] "X10.00.PM" "X9.15.PM" "X9.30.PM" "X9.45.PM" "X11.00.PM" "X10.15.PM" "X10.30.PM" "X10.45.PM"
[97] "X00.00.AM" "X11.15.PM" "X11.30.PM" "X11.45.PM" "X00.00.PM"
There noon and midnight are labelled as strings. The rest of the columns are labelled as times formats (in strings) but are also inconsistent in format. Lets change noon and midnight to the same format as the other times. We also want to create a uniform format across all the column names.
Melt the data. We want to change the data set from a wide format to a long format. Below are the top 6 rows.
Filter to the PM Peak hours, 2pm to 7pm.
PM_Peak <- c(14:19)
March_18_melt_PM_Peak <- March_18_melt %>%
filter(Hour>=14)%>%
filter(Hour<=19)
The new filtered data set only includes data between hour 14 and hour 19.
Lets find what detectors have bad values. We will create a list of Detector that contain records listed as ‘-1’. We will omit these detectors from our intial analysis.
var <- March_18_melt_PM_Peak %>%
group_by(Detector_ID)%>%
summarise(NAs =sum(Metric_value<0))%>%
arrange(NAs)%>%
filter(NAs==0)%>%
droplevels()
no_NAs <- as.vector(var$Detector_ID)
no_NAs
[1] "70" "72" "105" "115" "119" "147" "148" "149" "150" "151" "157" "158" "159" "160" "162" "232" "233" "234"
[19] "236" "237" "239" "240" "241" "242" "243" "244" "245" "246" "247" "248" "249" "250" "251" "252" "253" "271"
[37] "272" "273" "274" "275" "276" "277" "278" "279" "280" "281" "282" "287" "288" "289" "290" "291" "292" "351"
[55] "354" "355" "389" "406" "458" "459" "460" "462" "463" "464" "465" "466" "467" "487" "541" "545" "571" "572"
[73] "573" "577" "579" "582" "583" "591" "729" "806" "807" "817" "818" "819" "820" "821" "822" "823" "824" "825"
[91] "826" "827" "828" "829" "830" "831" "832" "833" "834" "836" "837" "838" "839" "840" "841" "842" "849" "850"
[109] "851" "852" "853" "854" "855" "856" "857" "858" "862" "863" "867" "868" "869" "870" "871" "872" "873" "874"
[127] "875" "876" "877" "878" "879" "880" "881" "882" "883" "884" "885" "886" "887" "894" "895" "896" "995" "996"
[145] "997" "998" "999" "1000" "1001" "1176" "1177" "1179" "1180" "1181" "1182" "1183" "1184" "1185" "1186" "1187" "1192" "1195"
[163] "1196" "1197" "1198" "1199" "1200" "1206" "1207" "1208" "1209" "1210" "1211" "1212" "1214" "1215" "1217" "1218" "1219" "1220"
[181] "1222" "1223" "1224" "1225" "1231" "1232" "1233" "1234" "1235" "1236" "1237" "1238" "1247" "1248" "1249" "1250" "1251" "1252"
[199] "1255" "1256" "1257" "1258" "1259" "1260" "1261" "1262" "1298" "1299" "1300" "1301" "1302" "1303" "1304" "1305" "1435" "1461"
[217] "1467" "1468" "1472" "1473" "1474" "1484" "1485" "1486" "1487" "1490" "1492" "1493" "1494" "1496" "1497" "1499" "1500" "1501"
[235] "1502" "1504" "1505" "1506" "1507" "1508" "1529" "1530" "1531" "1532" "1533" "1534" "1535" "1536" "1538" "1540" "1541" "1544"
[253] "1545" "1546" "1547" "1548" "1549" "1550" "1551" "1552" "1553" "1590" "1591" "1592" "1597" "1598" "1600" "1601" "1602" "1603"
[271] "1604" "1605" "1606" "1607" "1608" "1609" "1610" "1611" "1612" "1613" "1619" "1620" "1621" "3290" "3291" "3324" "3325" "3326"
[289] "3333" "3334" "3337" "3338" "3339" "3340" "3406" "3407" "3409" "3419" "3927" "3929" "3930" "3931" "3932" "3933" "3934" "3941"
[307] "3942" "3943" "3944" "3945" "3946" "3953" "4068" "4069" "4070" "4071" "4072" "4153" "4154" "4155" "4156" "4157" "4158" "5184"
[325] "5185" "5186" "5187" "5192" "5193" "5194" "5666" "5667" "5668" "5690" "5691" "5692" "5693" "6298" "6797" "6816" "6817" "6818"
[343] "6908" "6909" "6911" "6912" "6913" "6914" "6915" "6916" "6917" "6918" "6919" "6920" "6921" "6922" "6923" "6924" "6925" "7100"
[361] "7101" "7102" "7105" "7106" "7109" "7111" "7529" "7531" "7532" "7533" "7534" "7535" "7536" "7537" "7538" "7716" "7717" "7718"
There are 378 detectors that do not contain a -1 value.
Time Series
Lets pick Detector 70. We want to create a variable for each day and them sum the volumes for each day.
Now we create a time series for the data.
We decompose the Time Series to extract the trend, seasonality and remainder from the time series.

Day selection is ?.
Correlation
Show plots of volumes by day
y <- March_18_melt_PM_Peak %>%
mutate(Weekday = weekdays(Date_Time,abbreviate=TRUE),
YearDay=yday(Date_Time),
MonthDay=day(Date_Time),
HourMin = as.numeric(format(Date_Time,"%H.%M")))%>%
filter(Metric=='Volume')%>%
filter(Detector_ID%in%c(147:151))%>%
filter(Weekday %in% c('Tue','Wed','Thu'))
ggplot(y,aes(x=Metric_value,color=as.factor(Detector_ID)))+
geom_density()+facet_wrap(~MonthDay,nrow=4,scales = 'free_x')
Create detector ~ day heatmap. Each cell represents the covariance of the difference between each measurement. We have picked 100 detectors from the list for display purposes. All of the detectors shown do not contain any -1 values.
Invalid value for Colv, ignoring
Cluster Days
day_SDev <- March_18_melt_PM_Peak %>%
mutate(Weekday = weekdays(Date_Time,abbreviate=TRUE),
YearDay=yday(Date_Time),
MonthDay=day(Date_Time),
HourMin = as.numeric(format(Date_Time,"%H.%M")))%>%
filter(Metric=='Volume')%>%
group_by(Detector_ID,Date_Posixct)%>%
summarise(SumVol = sum(Metric_value))%>%
group_by(Date_Posixct)%>%
summarise(SDev = sd(SumVol))%>%
mutate(weekDay=weekdays(Date_Posixct,abbreviate=TRUE))
sundays <-day_SDev$Date_Posixct[day_SDev$weekDay%in%c('Sun')]
ggplot(day_SDev) +
geom_point(aes(Date_Posixct,SDev)) +
geom_rug(aes(Date_Posixct,SDev)) +
geom_vline(xintercept = sundays,linetype='dotted') +
theme_tufte(ticks = F) +
xlab("STD of the total volume across all Detectors") +
ylab("Date") +
theme(axis.title.x = element_text(vjust=-0.5), axis.title.y = element_text(vjust=1))
Cumulative running total
g <- March_18_melt_PM_Peak %>%
mutate(Weekday = weekdays(Date_Time,abbreviate=TRUE),
YearDay=yday(Date_Time),
MonthDay=day(Date_Time),
HourMin = as.numeric(format(Date_Time,"%H"))+
as.numeric(format(Date_Time,"%M"))/60)%>%
filter(Detector_ID==4069 & Metric=='Volume')%>%
# filter(YearDay==65 & Metric=='Volume')%>%
# filter(Detector_ID %in% no_NAs)%>%
# filter(Metric=='Volume')%>%
droplevels()%>%
group_by(YearDay)%>%
arrange(YearDay,HourMin)%>%
# group_by(Detector_ID,Date_Posixct)%>%
mutate(cumSum = cumsum(Metric_value),
lreg=lm(cumSum~HourMin)$coefficients[2],
correlation=cor(HourMin,cumSum),
cov=cov(HourMin,cumSum))
h <- g%>%
group_by(Date_Posixct)%>%
summarise(Correlation=first(correlation),
LIN=first(lreg),
cov=first(cov))%>%
mutate(wday = weekdays(Date_Posixct))%>%
arrange(Date_Posixct)
The below plot shows the cumulative summation of the peak hour volumes for each day in March 2018 for Detector 4069. The color scheme shows increasing covariance. Line to the bottom of the plot are Sundays and Saturdays.
The following plot displays straight volume across the peak hours for March for Detector 4069.
LS0tDQp0aXRsZTogIlIgTm90ZWJvb2siDQpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sNCi0tLQ0KDQpTZXQgd29ya2luZyBkaXJlY3RvcnkgYW5kIGxvYWQgbmVjZXNzYXJ5IHBhY2thZ2VzLg0KDQpgYGB7ciBzZXR1cCwgaW5jbHVkZT1GQUxTRX0NCmtuaXRyOjpvcHRzX2tuaXQkc2V0KHJvb3QuZGlyID0gIkg6L1Byb2plY3RzLzExMDAwLzExMTU1L1RyYWZmU3R1ZHkvRGF0YUNvbGxlY3Rpb24vRnJlZXdheURhdGEvRGV0ZWN0b3IgRGF0YS9Wb2x1bWUgRGF0YSIpDQoNCiMjYmVsb3cgYXJlIGEgbGlzdCBvZiBwYWNrYWdlcyByZXF1aXJlZCB0byBydW4gdGhlIG1hcmtkb3duIGZpbGUNCmxpYnJhcnkodGlkeXZlcnNlKQ0KbGlicmFyeShsdWJyaWRhdGUpDQpsaWJyYXJ5KGdyaWRFeHRyYSkNCmxpYnJhcnkocmVzaGFwZTIpDQpsaWJyYXJ5KHpvbykNCmxpYnJhcnkoaW1wdXRlVFMpDQpsaWJyYXJ5KHh0cykNCmxpYnJhcnkoZHlncmFwaHMpDQpsaWJyYXJ5KGQzaGVhdG1hcCkNCmxpYnJhcnkoZ2d0aGVtZXMpDQpsaWJyYXJ5KHBsb3RseSkNCg0KYGBgDQoNCkxvYWQgdGhlIGRhdGEgZm9yIE1hcmNoLiBMb2FkIGVhY2ggZmlsZSBhbmQgY29tYmluZSBpbnRvIG9uZSBkYXRhIHNldC4gV2UgbG9hZCBhbmQgY29tYmluZSBlYWNoIGZpbGUgaW4gYHIgZ2V0d2QoKWAuIFdlIG9ubHkgd2FudCB0byBsb2FkIHRoZSBmaWxlcyB0aGF0IGVuZCBpbiAiXyMuY3N2Ii4NCg0KYGBge3IgZXhwbG9yZSBNYXJjaCwgZWNobz1GQUxTRX0NCg0KZGlyKCcuL01hcmNoIDE4JykNCg0KYGBgDQoNCg0KDQpgYGB7ciBsb2FkIGRhdGEgZm9yIE1hcmNoLHdhcm5pbmc9RkFMU0UsZWNobz1GQUxTRX0NCnBhdGggPC0gJy4vTWFyY2ggMTgnDQoNCiMjIyBsaXN0IG91dCBhbGwgdGhlIGNzdiBmaWxlcyB0aGF0IHN0YXJ0IHdpdGggVFRfIGFuZCB0aGVuIGhhdmUgYSBudW1iZXIuIFRoaXMgd2lsbCBhdm9pZCBsb2FkaW5nIGluIHRoZSB1bndhbnRlZCBhZ2dyZWdhdGVkIGZpbGVzIG9yIFZNVCBmaWxlcy4NCiMjIydeX1xcZC4nIHJldHVybnMgYWxsIGZpbGVzIHRoYXQgZW5kIHdpdGggX3NvbWVfZGlnaXQuY3N2Lg0KbGlzdF9jc3YgPC0gZGlyKHBhdGg9cGF0aCxwYXR0ZXJuID0gJypfXFxkLmNzdicpDQoNCm15ZmlsZXMgPC0gbGFwcGx5KHBhc3RlKHBhdGgsJy8nLGxpc3RfY3N2LHNlcD0nJyksDQogICAgICAgICAgICAgICAgICBmdW5jdGlvbih4KSByZWFkLmNzdih4LHN0cmluZ3NBc0ZhY3RvcnMgPSBGQUxTRSkpDQoNCmZpbGVzIDwtIG1hcHBseShjYmluZCxteWZpbGVzLCdmaWxlbmFtZScgPSBsaXN0X2NzdixTSU1QTElGWSA9IEYpDQoNCmRhdCA8LSBiaW5kX3Jvd3MoZmlsZXMpDQoNCnJtKG15ZmlsZXMsZmlsZXMpDQoNCiNjcmVhdGUgYSBkYXRhc2V0IHRoYXQgd2Ugd2lsbCBlZGl0Li4uLg0KTWFyY2hfMThfZGF0IDwtIGRhdA0KYGBgDQoNClRoZSBjb2x1bW4gbmFtZXMgaW4gZWFjaCBmaWxlIGFyZSBhbHNvIGZvbGxvd3MuIA0KDQpgYGB7ciBleGFtaW5lIGNvbHVtbnMsIGVjaG89RkFMU0V9DQoNCmNvbG5hbWVzKE1hcmNoXzE4X2RhdCkNCmBgYA0KDQpMZXRzIGZpeCB0aGUgY29sdW1uIGhlYWRlcnMgZmlyc3QuIFRoZXJlIGFyZSBubyBoZWFkZXJzIGZvciB0aGUgZmlyc3QgMyBjb2x1bW5zIGFuZCBhbHNvIHRoZXJlIGFwcGVhcnMgdG8gYmUgYSBjb2x1bW4gYXQgdGhlIGVuZCBvZiB0aGUgZGF0YSBmcmFtZSAiWC4zIg0KDQpgYGB7ciBzdXltbWFyeSBvZiBkYXRhc2V0fQ0Kc3VtbWFyeShNYXJjaF8xOF9kYXQkWC4zKQ0KYGBgDQoNCkFsbCBOQXMuLi4uIHJlbW92ZS4NCg0KYGBge3IgcmVtb3ZlIGJsYW5rIGxhc3QgY29sdW1uLCBlY2hvPUZBTFNFfQ0KDQpNYXJjaF8xOF9kYXQgPC0gTWFyY2hfMThfZGF0WywhbmFtZXMoTWFyY2hfMThfZGF0KSA9PSAiWC4zIl0NCg0KYGBgDQoNCkZvY3VzIG9uIHRoZSBmaXJzdCB0aHJlZSBjb2x1bW5zOw0KDQpgYGB7ciBleGFtaW5lIGZpcnN0IDMgcm93cyxlY2hvPUZBTFNFfQ0Kc3RyKE1hcmNoXzE4X2RhdFsxOjNdKQ0KYGBgDQoNCkNvbHVtbiAxIGlzIHRoZSBkZXRlY3RvciBJRC48YnIvPg0KQ29sdW1uIDIgaXMgdGhlIG1ldHJpYy48YnIvPg0KQ29sdW1uIDMgaXMgdGhlIGRhdGUuPGJyLz4NCg0KDQpgYGB7ciBjaGFuZ2UgZmlyc3QgMyBjb2x1bW4gbmFtZXMsIGVjaG89RkFMU0V9DQoNCmNvbG5hbWVzKE1hcmNoXzE4X2RhdClbMTozXSA8LSBjKCdEZXRlY3Rvcl9JRCcsJ01ldHJpYycsJ0RhdGUnKQ0KDQpgYGANCg0KTm93IGxldHMgY2hhbmdlIHRoZSBkYXRhIHR5cGVzIGluIHRoZSBjb2x1bW5zLg0KDQpXZSBjcmVhdGUgYSBjb3JyZWN0bHkgZm9ybWF0dGVkIGRhdGUgZmllbGQgZnJvbSB0aGUgJ0RhdGUnIGZpZWxkLjxici8+DQpXZSBsYWJlbCB0aGUgZmllbGQgd2l0aCBkaXNwbGF5cyB0aGUgcmVjb3JkcyB0eXBlIGkuZS4gRGVuc2l0eSB2cyBTcGVlZCB2cyBWb2x1bWUgYXMgJ01ldHJpYycgYW5kIGNoYW5nZSBpdCBmcm9tIGEgc3RyaW5nIHRvIGEgZmFjdG9yIGZpZWxkLjxici8+DQpXZSBhbHNvIGNoYW5nZSBEZXRlY3Rvcl9JRCBmcm9tIGEgbnVtZXJpYyBmaWVsZCB0byBhIGZhY3RvciBmaWVsZC4NCg0KYGBge3IgbWV0cmljIGFuZCBEYXRlX3Bvc2l4Y3QsZWNobz1GQUxTRSxpbmNsdWRlPUZBTFNFfQ0KDQpNYXJjaF8xOF9kYXQkTWV0cmljIDwtIGFzLmZhY3RvcihNYXJjaF8xOF9kYXQkTWV0cmljKQ0KTWFyY2hfMThfZGF0JERhdGVfUG9zaXhjdCA8LSBhcy5QT1NJWGN0KE1hcmNoXzE4X2RhdCREYXRlLGZvcm1hdD0iJVkvJW0vJWQiKQ0KTWFyY2hfMThfZGF0JERldGVjdG9yX0lEIDwtIGFzLmZhY3RvcihNYXJjaF8xOF9kYXQkRGV0ZWN0b3JfSUQpDQojIyBDaGVjayB0aGF0IG91ciBkYXRlcyB3b3JrZWQgb3V0LiBXZSBkb24ndCB3YW50IGFueSBOQXMuDQp0YWJsZShNYXJjaF8xOF9kYXQkRGF0ZV9Qb3NpeGN0KQ0KDQpgYGANCg0KDQoNCmBgYHtyIFRpbWUgZmllbGR9DQoNCmNvbG5hbWVzKE1hcmNoXzE4X2RhdCkNCmBgYA0KDQoNClRoZXJlIG5vb24gYW5kIG1pZG5pZ2h0IGFyZSBsYWJlbGxlZCBhcyBzdHJpbmdzLiBUaGUgcmVzdCBvZiB0aGUgY29sdW1ucyBhcmUgbGFiZWxsZWQgYXMgdGltZXMgZm9ybWF0cyAoaW4gc3RyaW5ncykgYnV0IGFyZSBhbHNvIGluY29uc2lzdGVudCBpbiBmb3JtYXQuIExldHMgY2hhbmdlIG5vb24gYW5kIG1pZG5pZ2h0IHRvIHRoZSBzYW1lIGZvcm1hdCBhcyB0aGUgb3RoZXIgdGltZXMuIFdlIGFsc28gd2FudCB0byBjcmVhdGUgYSB1bmlmb3JtIGZvcm1hdCBhY3Jvc3MgYWxsIHRoZSBjb2x1bW4gbmFtZXMuDQoNCg0KYGBge3IgY2hhbmdlIG5vb24gbWlkbmlnaHQgbmFtZXMsZWNobz1GQUxTRX0NCg0KY29sbmFtZXMoTWFyY2hfMThfZGF0KVtjb2xuYW1lcyhNYXJjaF8xOF9kYXQpJWluJQ0KICAgICAgICAgICAgICAgICAgICAgICAgIGMoJ1gxLkFNJywnWDIuQU0nLCdYMy5BTScsJ1g0LkFNJywnWDUuQU0nLCdYNi5BTScsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAnWDcuQU0nLCdYOC5BTScsJ1g5LkFNJywnWDEwLkFNJywnWDExLkFNJywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICdYMS5QTScsJ1gyLlBNJywnWDMuUE0nLCdYNC5QTScsJ1g1LlBNJywnWDYuUE0nLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgJ1g3LlBNJywnWDguUE0nLCdYOS5QTScsJ1gxMC5QTScsJ1gxMS5QTScsJ05vb24nLCdNaWRuaWdodCcpXSA8LQ0KICBjKCdYMS4wMC5BTScsJ1gyLjAwLkFNJywnWDMuMDAuQU0nLCdYNC4wMC5BTScsJ1g1LjAwLkFNJywnWDYuMDAuQU0nLA0KICAgICdYNy4wMC5BTScsJ1g4LjAwLkFNJywnWDkuMDAuQU0nLCdYMTAuMDAuQU0nLCdYMTEuMDAuQU0nLA0KICAgICdYMS4wMC5QTScsJ1gyLjAwLlBNJywnWDMuMDAuUE0nLCdYNC4wMC5QTScsJ1g1LjAwLlBNJywnWDYuMDAuUE0nLA0KICAgICdYNy4wMC5QTScsJ1g4LjAwLlBNJywnWDkuMDAuUE0nLCdYMTAuMDAuUE0nLCdYMTEuMDAuUE0nLCdYMDAuMDAuQU0nLCdYMDAuMDAuUE0nKQ0KDQpNYXJjaF8xOF9kYXQgPC0gTWFyY2hfMThfZGF0ICU+JSBzZWxlY3QoRGV0ZWN0b3JfSUQsTWV0cmljLERhdGUsRGF0ZV9Qb3NpeGN0LGZpbGVuYW1lLGV2ZXJ5dGhpbmcoKSkNCg0KDQpgYGANCg0KTWVsdCB0aGUgZGF0YS4gV2Ugd2FudCB0byBjaGFuZ2UgdGhlIGRhdGEgc2V0IGZyb20gYSB3aWRlIGZvcm1hdCB0byBhIGxvbmcgZm9ybWF0LiBCZWxvdyBhcmUgdGhlIHRvcCA2IHJvd3MuDQoNCmBgYHtyIG1lbHQsZWNobz1GQUxTRX0NCg0KTWFyY2hfMThfbWVsdCA8LSBtZWx0KE1hcmNoXzE4X2RhdCxpZC52YXJzID0gYygnRGV0ZWN0b3JfSUQnLCdNZXRyaWMnLCdEYXRlJywnRGF0ZV9Qb3NpeGN0JywnZmlsZW5hbWUnKSx2YXJpYWJsZS5uYW1lID0gIlRpbWUiLHZhbHVlLm5hbWUgPSAnTWV0cmljX3ZhbHVlJykNCg0KaGVhZChNYXJjaF8xOF9tZWx0KQ0KYGBgDQoNCg0KDQpgYGB7ciBEYXRlX1RpbWUsIGVjaG89RkFMU0V9DQoNCiNyZW1vdmUgWA0KTWFyY2hfMThfbWVsdCRUaW1lIDwtIGdzdWIoJ1gnLCcnLE1hcmNoXzE4X21lbHQkVGltZSkNCg0KTWFyY2hfMThfbWVsdCREYXRlX1RpbWUgPC0gYXMuUE9TSVhjdChwYXN0ZShNYXJjaF8xOF9tZWx0JERhdGUsTWFyY2hfMThfbWVsdCRUaW1lKSxmb3JtYXQ9IiVZLyVtLyVkICVJLiVNLiVwIikNCg0KTWFyY2hfMThfbWVsdCRIb3VyIDwtIGhvdXIoTWFyY2hfMThfbWVsdCREYXRlX1RpbWUpDQoNCmBgYA0KDQpGaWx0ZXIgdG8gdGhlIFBNIFBlYWsgaG91cnMsIDJwbSB0byA3cG0uDQoNCmBgYHtyIFBlYWsgSG91cnN9DQoNClBNX1BlYWsgPC0gYygxNDoxOSkNCg0KTWFyY2hfMThfbWVsdF9QTV9QZWFrIDwtIE1hcmNoXzE4X21lbHQgJT4lDQogIGZpbHRlcihIb3VyPj0xNCklPiUNCiAgZmlsdGVyKEhvdXI8PTE5KQ0KDQpgYGANCg0KVGhlIG5ldyBmaWx0ZXJlZCBkYXRhIHNldCBvbmx5IGluY2x1ZGVzIGRhdGEgYmV0d2VlbiBob3VyIGByIG1pbihNYXJjaF8xOF9tZWx0X1BNX1BlYWskSG91cilgIGFuZCBob3VyIGByIG1heChNYXJjaF8xOF9tZWx0X1BNX1BlYWskSG91cilgLg0KDQpMZXRzIGZpbmQgd2hhdCBkZXRlY3RvcnMgaGF2ZSBiYWQgdmFsdWVzLiBXZSB3aWxsIGNyZWF0ZSBhIGxpc3Qgb2YgRGV0ZWN0b3IgdGhhdCBjb250YWluIHJlY29yZHMgbGlzdGVkIGFzICctMScuIFdlIHdpbGwgb21pdCB0aGVzZSBkZXRlY3RvcnMgZnJvbSBvdXIgaW50aWFsIGFuYWx5c2lzLiANCg0KYGBge3IgTkEgdmFsdWVzfQ0KDQp2YXIgPC0gTWFyY2hfMThfbWVsdF9QTV9QZWFrICU+JSANCiAgZ3JvdXBfYnkoRGV0ZWN0b3JfSUQpJT4lDQogIHN1bW1hcmlzZShOQXMgPXN1bShNZXRyaWNfdmFsdWU8MCkpJT4lDQogIGFycmFuZ2UoTkFzKSU+JQ0KICBmaWx0ZXIoTkFzPT0wKSU+JQ0KICBkcm9wbGV2ZWxzKCkNCiAgDQpub19OQXMgPC0gYXMudmVjdG9yKHZhciREZXRlY3Rvcl9JRCkNCm5vX05Bcw0KYGBgDQoNClRoZXJlIGFyZSBgciBsZW5ndGgobm9fTkFzKWAgZGV0ZWN0b3JzIHRoYXQgZG8gbm90IGNvbnRhaW4gYSAtMSB2YWx1ZS4NCg0KIyNUaW1lIFNlcmllcw0KDQpMZXRzIHBpY2sgRGV0ZWN0b3IgNzAuIFdlIHdhbnQgdG8gY3JlYXRlIGEgdmFyaWFibGUgZm9yIGVhY2ggZGF5IGFuZCB0aGVtIHN1bSB0aGUgdm9sdW1lcyBmb3IgZWFjaCBkYXkuDQoNCg0KYGBge3IgZGV0XzcwLGVjaG89RkFMU0V9DQoNCkRldF83MCA8LSAgTWFyY2hfMThfbWVsdF9QTV9QZWFrICU+JQ0KICBmaWx0ZXIoRGV0ZWN0b3JfSUQ9PTE1MCklPiUNCiAgZmlsdGVyKE1ldHJpYz09IlZvbHVtZSIpJT4lDQogIG11dGF0ZShZZWFyRGF5PXlkYXkoRGF0ZV9UaW1lKSwNCiAgICAgICAgIFdlZWtkYXk9d2Vla2RheXMoRGF0ZV9UaW1lLGFiYnJldmlhdGU9VFJVRSkpJT4lDQogICMgZmlsdGVyKFdlZWtkYXkgJWluJSBjKCdUdWUnLCdXZWQnLCdUaHUnKSklPiUNCiAgZ3JvdXBfYnkoRGF0ZV9Qb3NpeGN0KSU+JQ0KICBzdW1tYXJpc2UoU3VtVm9sID0gc3VtKE1ldHJpY192YWx1ZSkpDQoNCmhlYWQoRGV0XzcwKQ0KYGBgDQoNCg0KTm93IHdlIGNyZWF0ZSBhIHRpbWUgc2VyaWVzIGZvciB0aGUgZGF0YS4NCg0KYGBge3IgVGltZSBTZXJpZXMsZmlnLndpZHRoPTksZmlnLmhlaWdodD01LGVjaG89RkFMU0V9DQoNCkRldF83MF90c194dHMgPC0geHRzKERldF83MCRTdW1Wb2wsb3JkZXIuYnkgPSBEZXRfNzAkRGF0ZV9Qb3NpeGN0KQ0KDQpkeWdyYXBoKHh0cyhEZXRfNzAkU3VtVm9sLG9yZGVyLmJ5ID0gRGV0XzcwJERhdGVfUG9zaXhjdCkpJT4lDQogIGR5U2VyaWVzKGxhYmVsID0gJ1RvdGFsIFZvbC4nKSU+JQ0KICBkeVJhbmdlU2VsZWN0b3IoKQ0KYGBgDQoNCldlIGRlY29tcG9zZSB0aGUgVGltZSBTZXJpZXMgdG8gZXh0cmFjdCB0aGUgdHJlbmQsIHNlYXNvbmFsaXR5IGFuZCByZW1haW5kZXIgZnJvbSB0aGUgdGltZSBzZXJpZXMuIA0KDQpgYGB7ciBkZWNvbXBvc2UgZGF0YSwgZWNobz1GQUxTRX0NCkRldF83MF90cyA8LSB0cyhEZXRfNzAkU3VtVm9sLGZyZXF1ZW5jeT0zKQ0KDQpEZXRfNzBfdHNfZGVvbXAgPC0gZGVjb21wb3NlKERldF83MF90cykNCg0KRGV0XzcwX3RzX3N0bCA8LSBzdGwoRGV0XzcwX3RzLHMud2luZG93ID0gJ3BlcmlvZGljJykNCg0KbWlkd2VlayA8LSBjKCdUdWVzZGF5JywnV2VkbmVzZGF5JywnVGh1cnNkYXknKQ0KDQpwbG90KERldF83MF90c19zdGwpDQoNCmRheV9zZWxlY3QgPC0gIGNiaW5kKGRhdGEuZnJhbWUoRGV0XzcwX3RzX3N0bCR0aW1lLnNlcmllc1ssMTozXSksRGF0ZT1EZXRfNzAkRGF0ZV9Qb3NpeGN0LFdlZWtkYXk9d2Vla2RheXMoRGV0XzcwJERhdGVfUG9zaXhjdCkpJT4lDQogICMgbXV0YXRlKFJlc2lkID0gYWJzKHJlbWFpbmRlcikpJT4lDQogIGZpbHRlcihXZWVrZGF5ICVpbiUgbWlkd2VlayklPiUNCiAgYXJyYW5nZShyZW1haW5kZXIpJT4lDQogIHByaW50KCkNCg0KYGBgDQoNCg0KRGF5IHNlbGVjdGlvbiBpcyA/Lg0KDQojIyBDb3JyZWxhdGlvbg0KDQpTaG93IHBsb3RzIG9mIHZvbHVtZXMgYnkgZGF5DQoNCmBgYHtyIHBsb3QgdmFsdWVzfQ0KeSA8LSBNYXJjaF8xOF9tZWx0X1BNX1BlYWsgJT4lDQogIG11dGF0ZShXZWVrZGF5ID0gd2Vla2RheXMoRGF0ZV9UaW1lLGFiYnJldmlhdGU9VFJVRSksDQogICAgICAgICBZZWFyRGF5PXlkYXkoRGF0ZV9UaW1lKSwNCiAgICAgICAgIE1vbnRoRGF5PWRheShEYXRlX1RpbWUpLA0KICAgICAgICAgSG91ck1pbiA9IGFzLm51bWVyaWMoZm9ybWF0KERhdGVfVGltZSwiJUguJU0iKSkpJT4lDQogIGZpbHRlcihNZXRyaWM9PSdWb2x1bWUnKSU+JQ0KICBmaWx0ZXIoRGV0ZWN0b3JfSUQlaW4lYygxNDc6MTUxKSklPiUNCiAgZmlsdGVyKFdlZWtkYXkgJWluJSBjKCdUdWUnLCdXZWQnLCdUaHUnKSkNCg0KICBnZ3Bsb3QoeSxhZXMoeD1NZXRyaWNfdmFsdWUsY29sb3I9YXMuZmFjdG9yKERldGVjdG9yX0lEKSkpKw0KICBnZW9tX2RlbnNpdHkoKStmYWNldF93cmFwKH5Nb250aERheSxucm93PTQsc2NhbGVzID0gJ2ZyZWVfeCcpDQpgYGANCg0KDQpDcmVhdGUgZGV0ZWN0b3IgfiBkYXkgaGVhdG1hcC4gRWFjaCBjZWxsIHJlcHJlc2VudHMgdGhlIGNvdmFyaWFuY2Ugb2YgdGhlIGRpZmZlcmVuY2UgYmV0d2VlbiBlYWNoIG1lYXN1cmVtZW50LiBXZSBoYXZlIHBpY2tlZCAxMDAgZGV0ZWN0b3JzIGZyb20gdGhlIGxpc3QgZm9yIGRpc3BsYXkgcHVycG9zZXMuIEFsbCBvZiB0aGUgZGV0ZWN0b3JzIHNob3duIGRvIG5vdCBjb250YWluIGFueSAtMSB2YWx1ZXMuIA0KDQpgYGB7ciBoZWF0bWFwIGZvciBzdWJzZXQsZmlnLndpZHRoPTksZWNobz1GQUxTRX0NCg0KbGV2ZWxzIDwtIGxhc3QobGV2ZWxzKE1hcmNoXzE4X21lbHRfUE1fUGVhayREZXRlY3Rvcl9JRCksMTAwKQ0KDQptYXRyaXggPC0gTWFyY2hfMThfbWVsdF9QTV9QZWFrICU+JQ0KICBtdXRhdGUoV2Vla2RheSA9IHdlZWtkYXlzKERhdGVfVGltZSxhYmJyZXZpYXRlPVRSVUUpLA0KICAgICAgICAgWWVhckRheT15ZGF5KERhdGVfVGltZSksDQogICAgICAgICBNb250aERheT1kYXkoRGF0ZV9UaW1lKSwNCiAgICAgICAgIEhvdXJNaW4gPSBhcy5udW1lcmljKGZvcm1hdChEYXRlX1RpbWUsIiVIIikpKw0KICAgICAgICAgICBhcy5udW1lcmljKGZvcm1hdChEYXRlX1RpbWUsIiVNIikpLzYwKSU+JQ0KICBmaWx0ZXIoTWV0cmljPT0nVm9sdW1lJyklPiUNCiAgZmlsdGVyKERldGVjdG9yX0lEICVpbiUgbGV2ZWxzKSU+JQ0KICBmaWx0ZXIoRGV0ZWN0b3JfSUQgJWluJSBub19OQXMpJT4lDQogIGdyb3VwX2J5KERhdGVfUG9zaXhjdCxEZXRlY3Rvcl9JRCklPiUNCiAgYXJyYW5nZShEYXRlX1RpbWUpJT4lDQogIG11dGF0ZShjdW1TdW0gPSBjdW1zdW0oTWV0cmljX3ZhbHVlKSklPiUNCiAgbXV0YXRlKGNvcnJlbGF0aW9uID0gbG0oY3VtU3VtfkhvdXJNaW4pJGNvZWZmaWNpZW50c1syXSwNCiAgICAgICAgIGNvdj1jb3YoSG91ck1pbixjdW1TdW0pKSU+JQ0KICBhcnJhbmdlKERhdGVfUG9zaXhjdCkNCg0KDQptYXRyaXhfc3ByZWFkIDwtIG1hdHJpeCU+JQ0KICBncm91cF9ieShEYXRlX1Bvc2l4Y3QsRGV0ZWN0b3JfSUQpJT4lDQogICMgc3VtbWFyaXNlKGNvcnJlbGF0aW9uPWZpcnN0KGNvcnJlbGF0aW9uKSklPiUNCiAgc3VtbWFyaXNlKFZvbHVtZT1zdW0oTWV0cmljX3ZhbHVlKSklPiUNCiAgIyBzdW1tYXJpc2UoY292PWZpcnN0KGNvdikpJT4lDQogIHNwcmVhZChEYXRlX1Bvc2l4Y3QsVm9sdW1lKQ0KDQoNCnZlY3RvciA8LSBhcy5jaGFyYWN0ZXIobWF0cml4X3NwcmVhZCREZXRlY3Rvcl9JRCkNCm1hdHJpeDIgPC0gbWF0cml4X3NwcmVhZFssLTFdICU+JSBhcy5kYXRhLmZyYW1lKCkNCnJvd25hbWVzKG1hdHJpeDIpIDwtIHZlY3Rvcg0KZDNoZWF0bWFwKG1hdHJpeDIsc2NhbGUgPSAncm93JyxDb2x2ID0gJ2FzLWlzJyxjb2xvcnMgPSAnQmx1ZXMnKQ0KYGBgDQoNCkNsdXN0ZXIgRGF5cw0KDQpgYGB7cn0NCg0KZGF5X1NEZXYgPC0gTWFyY2hfMThfbWVsdF9QTV9QZWFrICU+JQ0KICBtdXRhdGUoV2Vla2RheSA9IHdlZWtkYXlzKERhdGVfVGltZSxhYmJyZXZpYXRlPVRSVUUpLA0KICAgICAgICAgWWVhckRheT15ZGF5KERhdGVfVGltZSksDQogICAgICAgICBNb250aERheT1kYXkoRGF0ZV9UaW1lKSwNCiAgICAgICAgIEhvdXJNaW4gPSBhcy5udW1lcmljKGZvcm1hdChEYXRlX1RpbWUsIiVILiVNIikpKSU+JQ0KICBmaWx0ZXIoTWV0cmljPT0nVm9sdW1lJyklPiUNCiAgZ3JvdXBfYnkoRGV0ZWN0b3JfSUQsRGF0ZV9Qb3NpeGN0KSU+JQ0KICBzdW1tYXJpc2UoU3VtVm9sID0gc3VtKE1ldHJpY192YWx1ZSkpJT4lDQogIGdyb3VwX2J5KERhdGVfUG9zaXhjdCklPiUNCiAgc3VtbWFyaXNlKFNEZXYgPSBzZChTdW1Wb2wpKSU+JQ0KICBtdXRhdGUod2Vla0RheT13ZWVrZGF5cyhEYXRlX1Bvc2l4Y3QsYWJicmV2aWF0ZT1UUlVFKSkNCg0Kc3VuZGF5cyA8LWRheV9TRGV2JERhdGVfUG9zaXhjdFtkYXlfU0RldiR3ZWVrRGF5JWluJWMoJ1N1bicpXQ0KDQpnZ3Bsb3QoZGF5X1NEZXYpICsgDQogIGdlb21fcG9pbnQoYWVzKERhdGVfUG9zaXhjdCxTRGV2KSkgKyANCiAgZ2VvbV9ydWcoYWVzKERhdGVfUG9zaXhjdCxTRGV2KSkgKyANCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gc3VuZGF5cyxsaW5ldHlwZT0nZG90dGVkJykgKw0KICB0aGVtZV90dWZ0ZSh0aWNrcyA9IEYpICsNCiAgeGxhYigiU1REIG9mIHRoZSB0b3RhbCB2b2x1bWUgYWNyb3NzIGFsbCBEZXRlY3RvcnMiKSArIA0KICB5bGFiKCJEYXRlIikgKyANCiAgdGhlbWUoYXhpcy50aXRsZS54ID0gZWxlbWVudF90ZXh0KHZqdXN0PS0wLjUpLCBheGlzLnRpdGxlLnkgPSBlbGVtZW50X3RleHQodmp1c3Q9MSkpDQoNCmBgYA0KDQpDdW11bGF0aXZlIHJ1bm5pbmcgdG90YWwNCg0KYGBge3IgY3Vtc3VtLCBmaWcud2lkdGg9OX0NCg0KZyA8LSBNYXJjaF8xOF9tZWx0X1BNX1BlYWsgJT4lDQogIG11dGF0ZShXZWVrZGF5ID0gd2Vla2RheXMoRGF0ZV9UaW1lLGFiYnJldmlhdGU9VFJVRSksDQogICAgICAgICBZZWFyRGF5PXlkYXkoRGF0ZV9UaW1lKSwNCiAgICAgICAgIE1vbnRoRGF5PWRheShEYXRlX1RpbWUpLA0KICAgICAgICAgSG91ck1pbiA9IGFzLm51bWVyaWMoZm9ybWF0KERhdGVfVGltZSwiJUgiKSkrDQogICAgICAgICAgIGFzLm51bWVyaWMoZm9ybWF0KERhdGVfVGltZSwiJU0iKSkvNjApJT4lDQogIGZpbHRlcihEZXRlY3Rvcl9JRD09NDA2OSAmIE1ldHJpYz09J1ZvbHVtZScpJT4lDQogICMgZmlsdGVyKFllYXJEYXk9PTY1ICYgTWV0cmljPT0nVm9sdW1lJyklPiUNCiAgIyBmaWx0ZXIoRGV0ZWN0b3JfSUQgJWluJSBub19OQXMpJT4lDQogICMgZmlsdGVyKE1ldHJpYz09J1ZvbHVtZScpJT4lDQogIGRyb3BsZXZlbHMoKSU+JQ0KICBncm91cF9ieShZZWFyRGF5KSU+JQ0KICBhcnJhbmdlKFllYXJEYXksSG91ck1pbiklPiUNCiAgIyBncm91cF9ieShEZXRlY3Rvcl9JRCxEYXRlX1Bvc2l4Y3QpJT4lDQogIG11dGF0ZShjdW1TdW0gPSBjdW1zdW0oTWV0cmljX3ZhbHVlKSwNCiAgICAgICAgIGxyZWc9bG0oY3VtU3VtfkhvdXJNaW4pJGNvZWZmaWNpZW50c1syXSwNCiAgICAgICAgIGNvcnJlbGF0aW9uPWNvcihIb3VyTWluLGN1bVN1bSksDQogICAgICAgICBjb3Y9Y292KEhvdXJNaW4sY3VtU3VtKSkNCg0KaCA8LSBnJT4lDQogIGdyb3VwX2J5KERhdGVfUG9zaXhjdCklPiUNCiAgc3VtbWFyaXNlKENvcnJlbGF0aW9uPWZpcnN0KGNvcnJlbGF0aW9uKSwNCiAgICAgICAgICAgIExJTj1maXJzdChscmVnKSwNCiAgICAgICAgICAgIGNvdj1maXJzdChjb3YpKSU+JQ0KICBtdXRhdGUod2RheSA9IHdlZWtkYXlzKERhdGVfUG9zaXhjdCkpJT4lDQogIGFycmFuZ2UoRGF0ZV9Qb3NpeGN0KQ0KYGBgDQoNClRoZSBiZWxvdyBwbG90IHNob3dzIHRoZSBjdW11bGF0aXZlIHN1bW1hdGlvbiBvZiB0aGUgcGVhayBob3VyIHZvbHVtZXMgZm9yIGVhY2ggZGF5IGluIE1hcmNoIDIwMTggZm9yIERldGVjdG9yIDQwNjkuIFRoZSBjb2xvciBzY2hlbWUgc2hvd3MgaW5jcmVhc2luZyBjb3ZhcmlhbmNlLiBMaW5lIHRvIHRoZSBib3R0b20gb2YgdGhlIHBsb3QgYXJlIFN1bmRheXMgYW5kIFNhdHVyZGF5cy4NCg0KYGBge3IgcGxvdCBjdW5zdW0sZWNobz1GQUxTRX0NCnBsb3QgPC0gZ2dwbG90KGcpICsgDQogIGdlb21fbGluZShhZXMoeD1Ib3VyTWluLHk9Y3VtU3VtLGdyb3VwPURhdGVfUG9zaXhjdCxjb2xvcj1jb3YpKSArIA0KICAjIGdlb21fcnVnKGFlcyh4PUhvdXJNaW4seT1jdW1TdW0pKSArIA0KICAjIGdlb21fc21vb3RoKGFlcyh4PUhvdXJNaW4seT1kaWZmKSkrDQogIHRoZW1lX3R1ZnRlKHRpY2tzID0gRikgKw0KICB4bGFiKCJIb3VyIikgKyANCiAgeWxhYigiQ3VtU3VtIikgKyANCiAgdGhlbWUoYXhpcy50aXRsZS54ID0gZWxlbWVudF90ZXh0KHZqdXN0PS0wLjUpLCBheGlzLnRpdGxlLnkgPSBlbGVtZW50X3RleHQodmp1c3Q9MSkpICANCg0KZ2dwbG90bHkocGxvdCkNCmBgYA0KDQpUaGUgZm9sbG93aW5nIHBsb3QgZGlzcGxheXMgc3RyYWlnaHQgdm9sdW1lIGFjcm9zcyB0aGUgcGVhayBob3VycyBmb3IgTWFyY2ggZm9yIERldGVjdG9yIDQwNjkuDQoNCmBgYHtyIHBsb3QyICAgdm9sdW1lLGVjaG89RkFMU0V9DQpwbG90MiA8LSBnZ3Bsb3QoZykgKyANCiAgZ2VvbV9saW5lKGFlcyh4PUhvdXJNaW4seT1NZXRyaWNfdmFsdWUsZ3JvdXA9RGF0ZV9Qb3NpeGN0LGNvbG9yPWNvdikpICsgDQogICMgZ2VvbV9ydWcoYWVzKHg9SG91ck1pbix5PWN1bVN1bSkpICsgDQogICMgZ2VvbV9zbW9vdGgoYWVzKHg9SG91ck1pbix5PWRpZmYpKSsNCiAgdGhlbWVfdHVmdGUodGlja3MgPSBGKSArDQogIHhsYWIoIkhvdXIiKSArIA0KICB5bGFiKCJWb2x1bWUiKSArIA0KICB0aGVtZShheGlzLnRpdGxlLnggPSBlbGVtZW50X3RleHQodmp1c3Q9LTAuNSksIGF4aXMudGl0bGUueSA9IGVsZW1lbnRfdGV4dCh2anVzdD0xKSkgIA0KDQpnZ3Bsb3RseShwbG90MikNCg0KYGBgDQoNCg0KDQo=